package com.example.gobang.game;


import com.example.gobang.GobangApplication;
import com.example.gobang.model.Point;
import com.example.gobang.model.User;
import com.example.gobang.model.UserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;


public class Room {

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    private String roomId;
    private User user1;
    private User user2;
    private int whiteUser;
    private boolean ai = false;

    public boolean isAi() {
        return ai;
    }

    public void setAi(boolean ai) {
        this.ai = ai;
    }

    // 棋盘, 数字 0 表示未落子位置. 数字 1 表示玩家 1 的落子. 数字 2 表示玩家 2 的落子
    private int[][] chessBoard = new int[MAX_ROW][MAX_COL];

    private AiPlayer aiPlayer;

    //@Autowired
    private OnlineUserManager onlineUserManager;
    //@Autowired
    private RoomManger roomManger;

    private UserMapper userMapper;

    private ObjectMapper objectMapper = new ObjectMapper();

    public int getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(int whiteUser) {
        this.whiteUser = whiteUser;
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }

    /**
     * 生成一个房间 ID
     */
    public Room(){
        roomId = UUID.randomUUID().toString();

        onlineUserManager = GobangApplication.context.getBean(OnlineUserManager.class);
        roomManger = GobangApplication.context.getBean(RoomManger.class);
        userMapper = GobangApplication.context.getBean(UserMapper.class);
        aiPlayer = GobangApplication.context.getBean(AiPlayer.class);
    }

    //落子
    public void putChess(String payload) throws IOException {
        GameRequest req = objectMapper.readValue(payload, GameRequest.class);
        GameResponse resp = new GameResponse();
        // 1. 进行落子
        int chess = req.getUserId() == user1.getUserId() ? 1 : 2;
        int row = req.getRow();
        int col = req.getCol();
        printChessBoard();
        if (chessBoard[row][col] != 0) {
            System.out.println("落子位置有误! " + req);
            return;
        }
        chessBoard[row][col] = chess;


        // 2. 检查游戏结束
        //    返回的 winner 为玩家的 userId
        int winner = checkWinner(chess, row, col);
        resp.setUserId(req.getUserId());
        resp.setRow(row);
        resp.setCol(col);
        resp.setWinner(winner);
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = null;
        if (user2.getUserId() != -1) {
            session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        }
        //3.玩家中途退出游戏
        if (session1 == null) {
            // 玩家1 掉线, 直接认为玩家2 获胜
            resp.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线!");
        }
        if (user2.getUserId() != -1 && session2 == null) {
            // 玩家2 掉线, 直接认为玩家1 获胜
            resp.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线!");
        }
        //4.返回响应
        if (session1 != null){
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        }
        if (session2 != null){
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        }
        //5. 如果玩家胜负已分, 就把 room 从管理器中销毁
        if (winner != 0){
            System.out.println("游戏结束! 房间即将销毁! roomId=" + roomId + " 获胜方为: " + resp.getWinner());
            int winUserId = resp.getWinner();
            int loseUserId = winUserId == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);
            Room room = roomManger.getRoomByUserId(req.getUserId());
            roomManger.remove(room,user1.getUserId(),user2.getUserId());
            return;
        }
        //轮到 ai 下
        if (user2.getUserId() == -1){
            GameResponse respAi = new GameResponse();
            MyAI myAI = new MyAI();
            Point position = myAI.getPosition(chessBoard);
            int x = position.getX();
            int y = position.getY();

            if (x > -1 && y > -1){
                respAi.setRow(x);
                respAi.setCol(y);
            }else {
                //相当于认输
                respAi.setWinner(user1.getUserId());
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(respAi)));
            }

            int winnerAi = checkWinner(2, x, y);
            respAi.setWinner(winnerAi);
            respAi.setUserId(user2.getUserId());
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(respAi)));
            //ai获胜后  玩家ai对局失败不扣分
            if (winner != 0){
                System.out.println("游戏结束! 房间即将销毁! roomId=" + roomId + " 获胜方为: " + resp.getWinner());
                Room room = roomManger.getRoomByUserId(req.getUserId());
                roomManger.remove(room,user1.getUserId(),-1);
            }
        }
    }

    //打印棋盘
    private void printChessBoard() {
        System.out.println("打印棋盘信息: "+roomId);
        System.out.println("===========================");
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < MAX_COL; c++) {
                System.out.print(chessBoard[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("===========================");
    }

    // 如果未分出胜负, 则返回 0
    // chess 值为 1 表示玩家1 的落子. 为 2 表示玩家2 的落子
    private int checkWinner(int chess, int row, int col) {
        // 以 row, col 为中心
        boolean done = false;
        // 1. 检查所有的行(循环五次)
        for (int c = col - 4; c <= col; c++) {
//            if (c < 0 || c >= MAX_COL) { //add c [+4]
//                continue;
//            }

            if (c < 0 || c + 4 >= MAX_COL) {
                continue;
            }

            if (chessBoard[row][c] == chess
                    && chessBoard[row][c + 1] == chess
                    && chessBoard[row][c + 2] == chess
                    && chessBoard[row][c + 3] == chess
                    && chessBoard[row][c + 4] == chess) {
                done = true;
            }
        }
        // 2. 检查所有的列(循环五次)
        for (int r = row - 4; r <= row; r++) {
//            if (r < 0 || r >= MAX_ROW) {
//                continue;
//            }

            if (r < 0 || r + 4 >= MAX_ROW) {
                continue;
            }

            if (chessBoard[r][col] == chess
                    && chessBoard[r + 1][col] == chess
                    && chessBoard[r + 2][col] == chess
                    && chessBoard[r + 3][col] == chess
                    && chessBoard[r + 4][col] == chess) {
                done = true;
            }
        }
        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
//            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
//                continue;
//            }

            if (r < 0 || r + 4 >= MAX_ROW || c < 0 || c + 4 >= MAX_COL) {
                continue;
            }

            if (chessBoard[r][c] == chess
                    && chessBoard[r + 1][c + 1] == chess
                    && chessBoard[r + 2][c + 2] == chess
                    && chessBoard[r + 3][c + 3] == chess
                    && chessBoard[r + 4][c + 4] == chess) {
                done = true;
            }
        }
        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
//            if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
//                continue;
//            }

            if (r < 0 || r + 4 >= MAX_ROW || c - 4 < 0 || c >= MAX_COL) {
                continue;
            }

            if (chessBoard[r][c] == chess
                    && chessBoard[r + 1][c - 1] == chess
                    && chessBoard[r + 2][c - 2] == chess
                    && chessBoard[r + 3][c - 3] == chess
                    && chessBoard[r + 4][c - 4] == chess) {
                done = true;
            }
        }
        if (!done) {
            return 0;
        }
        return chess == 1 ? user1.getUserId() : user2.getUserId();
    }
}
